package game.socket;

import dou.io.IDataInput;
import dou.net.protocol.AbstractProtocolClientSocket;
import dou.net.socket.IPacketBuffer;
import dou.net.socket.IServerSocket;
import dou.net.socket.SimplePacketBuffer;
import dou.scheduled.IntervalTaskManager;
import dou.scheduled.TimerManager;
import game.task.TaskManagerName;
import game.task.keepAlive.KeepAliveTask;
import game.utils.IPv4AddressUtil;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.zip.CRC32;

/**
 * 定义了一个远程套接字客户端
 * @author wizardc
 */
public class RemoteClientSocket extends AbstractProtocolClientSocket
{
    private static Logger logger = LogManager.getLogger("GameServer");

    /**
     * 客户端地址字符串
     */
    protected String _ipAddressStr;

    /**
     * 客户端地址
     */
    protected long _ipAddress;

    /**
     * 用户 ID
     */
    protected int _uid = -1;

    private KeepAliveTask _keepAliveTask;

    /**
     * 创建一个 RemoteClientSocket 对象
     * @param server 套接字服务对象
     * @param selector 套接字通道的 Selector 对象
     * @param socketChannel 套接字客户端的套接字通道对象
     * @throws IOException 当出现 IO 异常时抛出该异常
     */
    public RemoteClientSocket(IServerSocket server, Selector selector, SocketChannel socketChannel) throws IOException
    {
        super(server, selector, socketChannel);
        getIPv4Info();
    }

    private void getIPv4Info()
    {
        Socket socket = _socketChannel.socket();
        InetAddress address = socket.getInetAddress();
        _ipAddressStr = address.getHostAddress();
        _ipAddress =  new Long(IPv4AddressUtil.ip2Long(_ipAddressStr));
    }

    @Override
    public String ipAddressStr()
    {
        return _ipAddressStr;
    }

    /**
     * 获取客户端 IP 地址
     * @return 客户端 IP 地址
     */
    public long ipAddress()
    {
        return _ipAddress;
    }

    /**
     * 设置用户 ID
     * @param uid 用户 ID
     */
    public void uid(int uid)
    {
        _uid = uid;
    }

    /**
     * 获取用户 ID
     * @return 用户 ID
     */
    public int uid()
    {
        return _uid;
    }

    @Override
    protected IPacketBuffer createPacketBuffer()
    {
        return new SimplePacketBuffer();
    }

    @Override
    protected boolean checkMessageValid(IDataInput input)
    {
        /*
        // 获取客户端发送的验证消息
        long sendValue = input.readUnsignedInt();
        // 读取所有的数据
        int position = input.position();
        byte[] bytes = new byte[input.bytesAvailable()];
        input.readBytes(bytes);
        input.position(position);
        // 获取数据的验证消息
        CRC32 crc32 = new CRC32();
        crc32.update(bytes);
        long value = crc32.getValue();
        // 判断是否相等
        return sendValue == value;
        */
        return true;
    }

    /**
     * 启动心跳
     */
    public void startKeepAlive()
    {
        _keepAliveTask = new KeepAliveTask(this);

        IntervalTaskManager intervalTaskManager = (IntervalTaskManager) TimerManager.getInstance().getTaskManager(TaskManagerName.KeepAlive.getName());
        intervalTaskManager.addIntervalTask(_uid, _keepAliveTask);
    }

    /**
     * 接收到客户端的心跳包时调用
     */
    public void receiveClientKeepAlive()
    {
        _keepAliveTask.receiveClientKeepAlive();
    }

    /**
     * 心跳判断客户端掉线时会调用该方法
     */
    public void lostConnection()
    {
        try
        {
            this.close();
        }
        catch(IOException exception)
        {
            logger.error(exception);
        }
    }

    /**
     * 停止心跳
     */
    public void stopKeepAlive()
    {
        _keepAliveTask = null;

        IntervalTaskManager intervalTaskManager = (IntervalTaskManager) TimerManager.getInstance().getTaskManager(TaskManagerName.KeepAlive.getName());
        intervalTaskManager.removeIntervalTask(_uid);
    }

    @Override
    protected void closeHandler()
    {
        // 判断用户是否登录并有用户 ID 记录
        if(_uid > 0)
        {
            // 登出客户端
            ClientSocketManager.getInstance().logoutHandler(this);
        }
        else
        {
            logger.info("Socket client close now and the client never login!");
        }
        // 移除该连接上的套接字对象
        _server.remove(_socketChannel);
    }
}
